﻿
using System.Collections.Concurrent;
using System.IMServer.TextMessageCenter.DBModel;
using System.IMServer.TextMessageCenter.WSModels;
using System.Text.Json;
using System.Threading.Channels;

using GCC.Container.Abstracts;
using GCC.Container.Models;

using LuanNiao.JsonConverterExtends;

using WSClient = System.IMServer.Client.Manager;

namespace System.IMServer.TextMessageCenter
{
    public class MessageCenterServer
    {
        public static readonly MessageCenterServer Instance = new();
        private MessageCenterServer()
        {

            _opt = new JsonSerializerOptions(CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive);
            _opt.Converters.Add(new DateTime2StringConverter("yyyy-MM-dd"));
            _opt.Converters.Add(new Long2StringConverter());
        }
        /// <summary>
        /// 当前服务所有的客户端
        /// </summary>
        private readonly ConcurrentDictionary<string, AbsWebsocketDataClient<string>> _allClient = new();
        private AbsGCCLogger? _logger;
        /// <summary>
        /// 统一化序列化选项设置
        /// </summary>
        private readonly JsonSerializerOptions _opt;
        /// <summary>
        /// 消息信息元素channel
        /// </summary>
        private readonly Channel<IMMessages> _itemChannel = Channel.CreateUnbounded<IMMessages>();


        private AbsGCCContext? _context;
        public void Init(AbsGCCContext context, AbsGCCLoggerProvider provider)
        {
            _logger = provider.CreateLogger<MessageCenterServer>();
            _context = context;
            _context.OnWSConnectChanged += (__) =>
            {
                _ = Task.Run(() =>
                {
                    HandleUserWSInfo();

                });
            };
        }

        private void HandleUserWSInfo()
        {
            if (_context is null)
            {
                return;
            }
            var imRes = WSClient.GetAllUser("System", new GCCGrpc.IMServer.GetAllUserRequest() { });
            var uidList = imRes.Users.Select(item => item.UID).Distinct().ToList();

            var info = new UserOnline()
            {
                Type = "UserChanged",
            };
            uidList.ForEach(item =>
            {

                var clientList = _context.GetUserWSClient<string>(item);
                clientList.ForEach(client =>
                {
                    info.Users.Add(new UserOnline.UserDetail()
                    {
                        ClientID = client.ID,
                        ClientType = client.Type,
                        UID = item
                    });
                    var clientItem = ((AbsWebsocketDataClient<string>)client);
                    if (_allClient.TryAdd(clientItem.ID, clientItem))
                    {
                        HandleClientBinding(clientItem, item);
                    }
                });

            });


            _context.BoardCastTextMessage(
                Text.Json.JsonSerializer.Serialize(info, _opt));
        }



        public void Start()
        {
            if (GCCEntrance.DBManager!.LocalDB is null)
            {
                return;
            }
            _ = Task.Factory.StartNew(async () =>
            {
                var reader = _itemChannel.Reader;
                while (true)
                {
                    var asd = await reader.WaitToReadAsync();
                    var count = reader.Count;
                    var items = new List<IMMessages>();
                    while (items.Count < count)
                    {
                        items.Add(await reader.ReadAsync());
                    }
                    try
                    {
                        _ = GCCEntrance.DBManager!.LocalDB.Insert(items).ExecuteAffrows();
                    }
                    catch (Exception ex)
                    {
                        _logger?.Error($"Save IM message data to db error.", exception: ex);
                        continue;
                    }
                }

            }, TaskCreationOptions.LongRunning);
            _logger?.Information("IM text message server init completed.");

        }

        private void HandleClientBinding(AbsWebsocketDataClient<string> clientItem, long uid)
        {
            clientItem.OnDisposing += (string obj) =>
            {
                _ = _allClient.TryRemove(obj, out var clientItem);
            };
            clientItem.OnGotTextMessage += (string obj) =>
            {
                var instance = Text.Json.JsonSerializer.Deserialize<WSMessageRequest>(obj, _opt);
                if (instance is null)
                {
                    return;
                }
                if (instance.Type.Equals("SendMessage", StringComparison.CurrentCultureIgnoreCase))
                {
                    var message = Text.Json.JsonSerializer.Deserialize<UserSendMessage>(obj, _opt);
                    if (message is null || message.To == 0)
                    {
                        return;
                    }
                    message.From = uid;
                    message.FromClient = clientItem.ID;
                    message.FromClientType = clientItem.Type;
                    message.Token = "";

                    _ = WSClient.SendMessageToUserClient("IMServer text message center", new GCCGrpc.IMServer.SendMessageToUserClientRequest()
                    {
                        ClientID = message.ToClientID,
                        Text = JsonSerializer.Serialize(message, _opt),
                        UID = message.To
                    });
                    _ = _itemChannel.Writer.TryWrite(new IMMessages()
                    {
                        Content = obj,
                        From = uid,
                        FromClientType = clientItem.Type,
                        To = message.To,
                        ToClientType = message.ToClientType
                    });
                }

            };
        }

    }
}